using System;
using System.Xml;

using DesignByContract;

using Outcoding.GraphGenerator.Entities;
using Outcoding.GraphGenerator.Util.Logging;

namespace Outcoding.GraphGenerator.Composition
{
    public class ImageBuilder : BuilderBase {
        #region Attributes

        private string sourceAttr = "source";
        private string leftAttr = "left";
        private string topAttr = "top";
        private string widthAttr = "width";
        private string heightAttr = "height";

        #endregion

        private string mNodeName = XmlTagNames.image.ToString("g");

        private string mNodePath
        {
            get
            {
                return "./" + mNodeName;
            }
        }

        private XmlNode mNode;

        public XmlNode Node
        {
            get
            {
                return mNode;
            }
            set
            {
                mNode = value;
            }
        }

        public override void SelectNode(XmlDocument document) {
            throw new NotImplementedException();
        }

        public override void Compose()
        {
            try
            {
                this.BuildObject(mNode);
            }
            catch (PreconditionException preExc)
            {
                LogManager.Instance.LogWarning("Image entity could not be created; process aborted.", preExc);
            }
        }

        public override void Compose(XmlNode node)
        {
            mNode = node.SelectSingleNode(mNodePath);
            try
            {
                this.BuildObject(mNode);
            }
            catch (PreconditionException preExc)
            {
                LogManager.Instance.LogWarning("Image entity could not be created; process aborted.", preExc);
            }
        }

        private void BuildObject(XmlNode labelXmlNode) {
            Image image = new Image();
            try
            {
                if (labelXmlNode.Attributes[sourceAttr] != null)
                    image.Path = ParseSourceAttribute(labelXmlNode);
                if (labelXmlNode.Attributes[topAttr] != null)
                    image.Top = ParseTopAttribute(labelXmlNode);
                if (labelXmlNode.Attributes[leftAttr] != null)
                    image.Left = ParseLeftAttribute(labelXmlNode);
                if (labelXmlNode.Attributes[widthAttr] != null)
                    image.Width = ParseWidthAttribute(labelXmlNode);
                if (labelXmlNode.Attributes[heightAttr] != null)
                    image.Height = ParseHeightAttribute(labelXmlNode);
            }
            catch (DesignByContract.PreconditionException preExc) {
                //log error
                image = null;
                throw;
            }
            this.mProduct = image;
        }

        public override void AppendToParent(object parent){
            Check.Require(parent is Shape, "Parent object not a valid argument");
            ((Shape) parent).Content = (Image)this.mProduct;
        }

        private Uri ParseSourceAttribute(XmlNode imageXmlNode)
        {
            Check.Require(imageXmlNode.Attributes[sourceAttr] != null, "source attribute not present");
            try {
                UriBuilder uriBuilder = new UriBuilder(imageXmlNode.Attributes[sourceAttr].Value);
                return uriBuilder.Uri;
            }catch(Exception exc) {
                LogManager.Instance.LogWarning("image source is not a valid path.", exc);
                return new Uri("", UriKind.RelativeOrAbsolute);
            }
        }
        
        private int ParseTopAttribute(XmlNode imageXmlNode){
            Check.Require(imageXmlNode.Attributes[topAttr] != null, "top attribute not present");
            return Int32.Parse(imageXmlNode.Attributes[topAttr].Value);
        }

        private int ParseLeftAttribute(XmlNode imageXmlNode){
            Check.Require(imageXmlNode.Attributes[leftAttr] != null, "left attribute not present");
            return Int32.Parse(imageXmlNode.Attributes[leftAttr].Value);
        }

        private int ParseWidthAttribute(XmlNode imageXmlNode){
            Check.Require(imageXmlNode.Attributes[widthAttr] != null, "width attribute not present");
            return Int32.Parse(imageXmlNode.Attributes[widthAttr].Value);
        }

        private int ParseHeightAttribute(XmlNode imageXmlNode){
            Check.Require(imageXmlNode.Attributes[heightAttr] != null, "height attribute not present");
            return Int32.Parse(imageXmlNode.Attributes[heightAttr].Value);
        }
    }
}
